[Previous] [Next]

The TabStrip Control

Tabbed dialog boxes are standard these days among Windows applications. Visual Basic comes with two controls for implementing them: The TabStrip common control and the SSTab control. In this section, I describe the TabStrip control, whereas Chapter 12 covers the SSTab control.

The most important thing to learn about the TabStrip control is that it isn't a container. In other words, it offers a program only the ability to display a number of tabs and react to users' clicks on them. It's up to the developer to make a group of controls visible or invisible, depending on which tab is currently selected. This makes working with this control at design time a tedious job and is probably the reason why many developers prefer the SSTab control, which is a real container control and can swap pages at design time as well. In my opinion, this nuisance is balanced by the fact that TabStrip is more powerful in other areas.

The TabStrip control exposes a Tabs collection, which in turn contains Tab objects. You must be aware of this structure to exploit all the features of this control.

Setting Design-Time Properties

After you place a TabStrip control on a form, you have to set up a few general properties and then add a number of tabs. You can perform both operations from within the Properties custom dialog box, which you display by right-clicking on the control and selecting the Properties menu option.

General properties

You can set all general properties from the General tab of the Property Pages dialog box, as shown in Figure 10-19. The first property you might want to set is Style, which lets you change the appearance of the control. In most cases, you leave it with its default value 0-tabTabs (the control is rendered as a collection of tabbed pages), but you can also set it to 1-tabButtons (tabs are replaced by buttons, and no border is displayed) or 2-tabFlatButtons (same as tabButtons, but buttons are flat). In the latter two cases, you can opt for separators among buttons by setting the Separators property to True. A few combinations of these styles are visible in Figure 10-20.

The tabFlatButton setting has appeared for the first time in Visual Basic 6, together with the Separator property. Other new Visual Basic 6 properties are TabMinWidth, Placement, TabStyle, HotTracking, and MultiSelect.

Figure 10-19. The General tab of the Property Pages dialog box of a TabStrip control.

Click to view at full size.

Figure 10-20. A gallery of styles for the TabStrip control.

If you're going to add more tabs than can appear in a single line, you can create multiple lines of tabs by setting the MultiRow property to True. You can choose different justification styles for the tabs by setting the TabWidthStyle property to 0-tabJustified, 1-tabNonJustified, or 2-tabFixed. If you're working with tabs of fixed width, you can assign a suitable value to the TabFixedWidth and TabFixedHeight properties. If you're working with tabs of variable width, you can set a minimum value for their size using the TabMinWidth property.

The Placement property lets you decide whether tabs should appear near the top (default), bottom, left, or right border of the control. The TabStyle property affects the run-time behavior of TabStrip controls with multiple rows: When you set this property to 1-tabTabOpposite, all the rows that precede the current one are displayed on the opposite side of the control.

A few other design-time Boolean properties can affect the appearance of the control. You can set the HotTracking property to True to activate the hot tracking feature (but only if Style is tabFlatButtons). If the Multiselect property is True, the user can select multiple tabs by clicking on them while pressing the Ctrl key (but only if Style is tabButtons or tabFlatButtons). Finally, if the ShowTips property is True, the control displays the ToolTipText associated with the tab over which the user moves the mouse.

Tab objects

Once you've set the most important general properties, you can create tabs in the Tabs tab (sounds a bit confusing, yes? It's the second tab…) of the Property Pages dialog box. The only property that isn't optional is the Caption property. The Key property is the value that identifies a tab in the Tabs collection, whereas Tag and ToolTipText have the usual meanings and effects.

You can display an icon in each tab. To do that, you have to load all the images into a companion ImageList control and then store a reference to this control in the TabStrip's ImageList property. At this point, you can assign a Tab's Image property the index of the image that should be displayed.

Preparing the child containers

Because the TabStrip control isn't a container control, you can't place child controls directly on its surface. This is probably the most serious limitation of this control: Even if it doesn't affect the control's run-time potential, it surely makes the design-time phase a little cumbersome. At run time, it's up to the programmer to show all the controls on the tab being clicked by the user and hide the child controls belonging to all other tabs.

In practice, the most convenient way to manage the child controls is to create a number of container controls on the form—for example, PictureBox or Frame controls. These controls should belong to a control array so that you can easily manipulate them as a group. It isn't really important where you place these containers on the form because you'll have to move and resize them at run time.

Let's say that you have a TabStrip control with three tabs. You create three PictureBox controls, such as those visible in Figure 10-21, and then place child controls inside each PictureBox. I suggest that you move the containers to different positions so that you can easily select them at design time and bring them to the front using the Ctrl+J key combination. Things are easier if you use containers with visible borders and then hide the borders at run time.

Click to view at full size.

Figure 10-21. Using PictureBoxes to contain child controls of a TabStrip control.

Run-Time Operations

In most cases, you use only a fraction of the possibilities offered by the TabStrip control. In fact, the majority of applications just need to show the pages defined at design time and never need to create new ones. In this section, I describe the most common actions you can perform on this control using code.

Moving and resizing containers

If you have followed my advice about using Frame or PictureBox controls as containers for child controls, you need to move and resize them before the form becomes visible. You usually do it in the Form_Load event and exploit the properties ClientLeft, ClientTop, ClientWidth, and ClientHeight of the TabStrip control to learn where those containers should be moved. You also need to hide containers' borders, if they have any. The following code snippet assumes that all PictureBox container controls belong to the picTab control array:

Private Sub Form_Load()
    Dim pic As PictureBox
    For Each pic In picTab
        pic.Move TabStrip1.ClientLeft, TabStrip1.ClientTop, _
            TabStrip1.ClientWidth, TabStrip1.ClientHeight
        pic.BorderStyle = 0
    Next
End Sub

Selecting the current container

You react to the user's clicks by making the container control—the one that corresponds to the clicked tab—the only visible container. You can learn which tab has been clicked by querying the SelectedItem property:

Private Sub TabStrip1_Click()
    Dim pic As PictureBox
    For Each pic In picTab
        ' The expression on the right returns True for one picture box.
        ' (Control arrays are zero-based; Selected.Index is one-based.)
        pic.Visible = (pic.Index = TabStrip1.SelectedItem.Index - 1)
    Next     
End Sub

When the Click event fires, the SelectedItem property has already been set to the tab that's now current. If you want to keep track of which tab was current before the click, you must store this value in a form-level variable. Alternatively, you can trap the user's action before the Click event in the BeforeClick event. This event offers the program an opportunity to validate data on the current tab before the user leaves it and possibly to cancel the click. Here's an example of this technique:

Private Sub TabStrip1_BeforeClick(Cancel As Integer)
    Select Case TabStrip1.SelectedItem.Index
        Case 1
            ' Refuse to move until the user types something in this field.
            If txtUserName.Text = "" Then Cancel = True
        Case 2
            ' Validation code for second tab
        Case 3
            ' Validation code for third tab
    End Select
End Sub

You can also select a tab programmatically, by assigning a value to the SelectedItem property. You can use one of these two syntax forms:

' Both statements select the second tab.
Set TabStrip1.SelectedItem = TabStrip1.Tabs(2)
TabStrip1.Tabs(2).Selected = True

The BeforeClick and Click events fire even when a tab is selected through code.

Multiple Tab objects can have their Selected property set to True if the TabStrip's MultiSelect property is also True. You can quickly deselect all tabs using the DeselectAll method. Finally, you can highlight one or more tabs without showing their contents by setting the Highlighted property to True:

' Highlight the second tab.
TabStrip1.Tabs(2).Highlighted = True

Creating and removing Tab objects

You can create new tabs at run time, using the Add method of the Tabs collection, which has the following syntax:

Add([Index], [Key], [Caption], [Image]) As Tab

The Add method's arguments are the Index, Key, Caption, and Image properties of the Tab object being created. Because this method returns a reference to the created object, you can set additional properties using the following technique:

With TabStrip1.Add(, , "Authentication")
    .ToolTipText = "Click here to change authentication settings"
    .Tag = "ABC123"
End With

You can remove an existing Tab object at run time using the Tabs collection's Remove method, and you can remove all the tabs using the collection's Clear method.